<script lang='ts' setup>
import { onMounted, reactive } from 'vue'
import { Entry, resources_list } from '@/apis/toolbox/resources/resources_list.ts'
import ResourcesMakeDir from '@/components/toolbox/resources/ResourcesMakeDir.vue'
import ResourcesSaveFile from '@/components/toolbox/resources/ResourcesSaveFile.vue'
import ResourcesRemoveConfirm from '@/components/toolbox/resources/ResourcesRemoveConfirm.vue'
import { resources_read_file } from '@/apis/toolbox/resources/resources_read_file.ts'
import ResourcesMove from '@/components/toolbox/resources/ResourcesMove.vue'
import { generate_download_token } from '@/apis/basic/generate_download_token.ts'
import ResourcesUpload from '@/components/toolbox/resources/ResourcesUpload.vue'
import { resources_compress } from '@/apis/toolbox/resources/resources_compress.ts'
import { byte_format } from '@/funcs/byte_format.ts'
import { date_format } from '@/funcs/date_format.ts'
import { resources_decompress } from '@/apis/toolbox/resources/resources_decompress.ts'

declare type State = {
  current: string,
  path: string,
  loading: boolean,
  entries: Entry[],
  show_make_dir: boolean,
  show_save_file: boolean,
  name: string,
  content: string,
  readonly: boolean,
  show_remove: boolean,
  remove_path: string,
  show_move: boolean,
  source: string,
  show_uploading: boolean,
}

const state = reactive<State>({
  current: '/',
  path: '/',
  loading: false,
  entries: [],
  show_make_dir: false,
  show_save_file: false,
  name: '',
  content: '',
  readonly: false,
  show_remove: false,
  remove_path: '',
  show_move: false,
  source: '',
  show_uploading: false
})

onMounted(async () => {
  list().then()
})

async function list(): Promise<void> {
  if (!state.path.endsWith('/')) {
    state.path += '/'
  }

  state.loading = true
  const response = await resources_list(state.path)
  state.loading = false

  if (0 !== response.code) {
    window.$message.error(response.message)

    return
  }

  state.current = state.path
  state.entries = response.data.data
}

async function view(entry: Entry): Promise<void> {
  if (entry.is_dir) {
    state.path = state.current + entry.name + '/'

    return await list()
  }

  entry.viewing = true
  const response = await resources_read_file(state.current + entry.name)
  entry.viewing = false

  if (0 !== response.code) {
    window.$message.error(response.message)

    return
  }

  state.name = entry.name
  state.content = response.data.content
  state.readonly = true

  state.show_save_file = true
}

async function edit(entry: Entry): Promise<void> {
  if (entry.is_dir) {
    window.$message.error('目录不可编辑')

    return
  }

  entry.viewing = true
  const response = await resources_read_file(state.current + entry.name)
  entry.viewing = false

  if (0 !== response.code) {
    window.$message.error(response.message)

    return
  }

  state.name = entry.name
  state.content = response.data.content
  state.readonly = false

  state.show_save_file = true
}

async function move(entry: Entry): Promise<void> {
  state.source = state.current + entry.name
  state.show_move = true
}

async function back_to_root(): Promise<void> {
  state.path = "/"
  await list()
}

async function back(): Promise<void> {
  if ('/' == state.path) {
    return
  }

  const strings = state.path.split('/')
  state.path = strings.slice(0, strings.length - 2).join('/') + '/'

  await list()
}

async function compress(entry: Entry): Promise<void> {
  entry.compressing = true
  const response = await resources_compress(state.current + entry.name, 2)
  entry.compressing = false

  if (0 !== response.code) {
    window.$message.error(response.message)

    return
  }

  window.$message.info('开始压缩，请稍后')
  await list()
}

async function decompress(entry: Entry): Promise<void> {
  entry.compressing = true
  const response = await resources_decompress(state.current + entry.name)
  entry.compressing = false

  if (0 !== response.code) {
    window.$message.error(response.message)

    return
  }

  window.$message.info('开始解压，请稍后')
  await list()
}

async function download(entry: Entry): Promise<void> {
  entry.downloading = true
  const response = await generate_download_token()
  entry.downloading = false

  if (0 !== response.code) {
    window.$message.error(response.message)

    return
  }

  window.$message.success('文件即将开始下载')
  window.open(`/api/toolbox/resources/download?path=${encodeURI(state.current)}&name=${encodeURI(entry.name)}&downloader-temporary-token=${response.data.token}`)
}
</script>

<template>
  <n-space vertical>
    <div>
      <n-space :wrap-item='false' align='center'>
        <n-button :disabled='state.loading' size='small' type='default' @click='back_to_root'>返回根目录</n-button>
        <n-button :disabled='state.loading' size='small' type='default' @click='back'>返回上一级</n-button>
        <n-button :disabled='state.loading' size='small' type='default' @click='list'>刷新</n-button>
        <div class='flex-max'>
          <n-input-group>
            <n-input-group-label size='small'>路径</n-input-group-label>
            <n-input v-model:value='state.path' :disabled='state.loading' size='small'></n-input>
            <n-button :disabled='state.loading' size='small' type='primary' @click='list'>跳转</n-button>
          </n-input-group>
        </div>
        <n-button :disabled='state.loading' size='small' type='primary' @click='state.show_make_dir = true'>创建文件夹</n-button>
        <n-button :disabled='state.loading' size='small' type='primary' @click='state.show_save_file = true'>创建文件</n-button>
        <n-button :disabled='state.loading' size='small' type='primary' @click='state.show_uploading = true'>上传文件</n-button>
      </n-space>
    </div>
    <n-divider></n-divider>
    <div>
      <n-space vertical>
        <n-space :wrap-item='false' align='center'>
          <div class='flex-max'>文件名</div>
          <div style='width: 80px'>状态</div>
          <div style='width: 80px'>后缀名</div>
          <div style='width: 120px'>文件大小</div>
          <div style='width: 180px'>更新时间</div>
          <div style='width: 460px;'>
            <n-space align='center'>
              <n-text>操作</n-text>
            </n-space>
          </div>
        </n-space>
        <template v-for='(entry, index) in state.entries' :key='index'>
          <div :data-index='index' class='resources-entry'>
            <n-space :wrap-item='false' align='center'>
              <div class='flex-max'><span style='cursor: pointer' @click='view(entry)'>{{ entry.name }}{{ entry.is_dir ? '/' : '' }}</span></div>
              <div style='width: 80px'>{{ { 1: '', 2: '压缩中', 3: '解压中' }[entry.state] }}</div>
              <div style='width: 80px'>{{ entry.ext }}</div>
              <div style='width: 120px'>{{ !entry.is_dir ? (entry.size > 0 ? byte_format(entry.size) : 0) : '-' }}</div>
              <div style='width: 180px'>{{ date_format(entry.update_time * 1000, 'yyyy-MM-dd HH:mm:ss') }}</div>
              <div style='width: 460px;'>
                <n-space align='center' justify='space-between'>
                  <n-button :disabled='state.loading || entry.viewing || entry.is_compressed_file' size='small' type='primary' @click='view(entry)'>查看</n-button>
                  <n-button :disabled='state.loading || entry.is_dir || entry.is_compressed_file' size='small' type='primary' @click='edit(entry)'>编辑</n-button>
                  <n-button :disabled='state.loading' size='small' type='primary' @click='move(entry)'>移动</n-button>
                  <n-button :disabled='state.loading' size='small' type='primary' @click='compress(entry)'>压缩</n-button>
                  <n-button :disabled='state.loading || entry.is_dir || !entry.is_compressed_file' size='small' type='primary' @click='decompress(entry)'>解压</n-button>
                  <n-button :disabled='state.loading || entry.downloading || entry.is_dir' size='small' type='primary' @click='download(entry)'>下载</n-button>
                  <n-button :disabled='state.loading' size='small' type='error' @click='state.remove_path = state.current+entry.name; state.show_remove = true'>删除</n-button>
                </n-space>
              </div>
            </n-space>
          </div>
        </template>
      </n-space>
    </div>
  </n-space>
  <ResourcesMakeDir v-model:show='state.show_make_dir' :path='state.current' @success='list' />
  <ResourcesSaveFile v-model:show='state.show_save_file' :content='state.content' :name='state.name' :path='state.current' :readonly='state.readonly' @close='state.name = ""; state.content = ""; state.readonly = false' @success='list' />
  <ResourcesRemoveConfirm v-model:show='state.show_remove' :path='state.remove_path' @success='list' />
  <ResourcesMove v-model:show='state.show_move' :path='state.source' @success='list' />
  <ResourcesUpload v-model:show='state.show_uploading' :path='state.current' @success='list' />
</template>

<style scoped>
.resources-entry {
  border-bottom: 1px solid #2E4053;
  padding: 15px 0;
}
</style>
